
package doc2db.fileWorker;

import doc2db.Keey;
import doc2db.table.DocTable;
import javax.swing.JOptionPane;
import org.opu.translator.Lexer;
import org.opu.translator.Lexer.TwoString;

/**
 *  <p>Класс для обработки строк и выдиления в них
 * интересующей информации</p>
 * @author yuriy
 */
public class ParseHelper implements ParseHelperInterface {
    private String delimiter = "\\$"; //разделитель
    private static int tabNum = -1;

    /**
     * <p>Разбирает заданую строку находя в ней указанные
     * связки слов. Формирует двойной масив в котором
     * хранится название столбца и информация из строки
     * в соответсятвии с этим назуанием</p>
     * <p>Если какуюту ячеёку нельзя определить на её
     * место будет записан null</p>
     * @param sb задаваемоя строка, в которой мы
     * ищем информацию: все слова перед теблицей
     * @param arr масив связок слов, которые разбивают
     * заданую строку: описание дополнительных столбцов в
     * xml документе, к примеру "студентов группы $grup$, перевести ..."
     * @param tr выводить ли номер обрабатываемой таблици и
     * увеличивать ли его на 1
     * @return масив строк [2][n] , где [0][i] - это название зсголовка,
     * а [1][i] - это информация из строки. n - зависит от того сколько
     * столбцов необходимо добавить 
     */
    @Override
    public String [][] getInfoInSuggestion(StringBuffer sb, String [] arr, boolean tr){
        tabNum ++;
        try {
            Lexer lex = new Lexer(sb.toString().replaceAll("LINE_END", "\n"), arr);
            TwoString[] parseDate = lex.parseDate();
            return Lexer.toUnNormalArr(parseDate);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, 
                    "Ошибка при работе \"lex\" модуля:\n" +
                    e + "\n" +
                    "работа продолжится в регулярном режиме",
                    "doc2db - расширение таблицы", JOptionPane.ERROR_MESSAGE);
        }
        if (tr) {
            if(Keey.debug)
                System.out.println("   table " + (tabNum));
        }
        
        int numVar = 0; // определяем общую суму переменных в шаблоне определенно
        for (int i = 0; i < arr.length; i++) {
            if(arr[i].equals("null")){
                numVar++;
                continue;
            }

            try{
                if(arr[i].trim().equals("null")){
                    numVar++;
                    continue;
                }
            }catch(Exception exept){}

            String [] a = arr[i].split(delimiter);
            numVar += (a.length - 1) / 2;
        }

        //инициализируем массив для возвращения данных
        String [][] retStr = new String [2][numVar];
        if(numVar == 0){
            System.err.println("Empty statement");
            return new  String [][] {{"null"}, {"null"}};
        }
        numVar = 0;


        for (int iter = 0; iter < arr.length; iter++) {
            //если данный тег null
            if(arr[iter].equals("null")){
                retStr[0][numVar] = "null";
                retStr[1][numVar] = "null";
                numVar ++;
                continue;
            }

            Mc m = this.isAllInfo(sb, arr[iter]);
            if(m.b){
                retStr[0][numVar] = m.s1;
                retStr[1][numVar] = m.s2;
                numVar ++;
                continue;
            }

            String [] a = arr[iter].split(delimiter);
            if(a.length < 2){
                retStr[0][numVar] = "null";
                retStr[1][numVar] = "null";
                System.err.println("  >ParseHelper - incorrect assertion to little arguments : " + arr[iter]);
                continue;
            }

            int num = (a.length - 1) / 2;
            String initStr = "";
            try {
                initStr = this.getSuggestionStrFromParagraph(sb.toString(), a[0], a[a.length - 1]);
            } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) {
                retStr[0][numVar] = "null";
                retStr[1][numVar] = "null";
                System.err.println("  >ParseHelper - incorrect assertion can get arguments: " + arr[iter]);
                continue;
            }
            for(int i = 0 , j = 1 ; i < num ; i ++, j += 2){
                try {
                    retStr[0][numVar] = a[j];
                    retStr[1][numVar] = this.getStrBetweenTwoSubStr(initStr, a[j-1], a[j+1])
                            .replaceAll("LINE_END", " ").trim();
                } catch (ArrayIndexOutOfBoundsException e) {
                    retStr[0][numVar] = "null";
                    retStr[1][numVar] = "null";
                    System.err.println("  >ParseHelper - incorrect assertion can not select a line: " + arr[iter]);
                }
                //if(Keey.debug) System.out.println("  "+retStr[0][numVar]+"->"+retStr[1][numVar]);
                numVar ++;
            }
        }
        
        return retStr;
    }

    /**
     * ALL_INFO
     * @param sb
     * @param arr
     * @return
     */
    private Mc isAllInfo(StringBuffer sb, String arr) {
        Mc mc = new Mc();

        if(arr.length() < 20)
            return mc;

        String s1 = arr.substring(0, 9);
        String s2 = arr.substring(arr.length()-9, arr.length());
        String s3 = arr.substring(9, arr.length()-9);

        if(s1.equals("ALL_INFO$") && s2.equals("$ALL_INFO")){
            mc.b = true;
            String[] sB = s3.split("#");
            if(sB.length > 1){
                String [] sB2 = sB[1].split(",");
                for (int i = 0; i < sB2.length; i++) {
                    try {
                        if(Integer.parseInt(sB2[i].trim())==tabNum){
                            mc.b = false;
                            return mc;
                        }
                    } catch (NumberFormatException numberFormatException) {
                    }
                }
            }
            
            mc.s1 = s3.split("#")[0].replace('\"', '`');
            mc.s2 = sb.toString().replaceAll("LINE_END", " ").trim().replace('\'', '`');
            
        }
        
        return mc;
    }

    private class Mc {
        boolean b = false;
        String s1 = "";
        String s2 = "";
    }

    /**
     *  <p>Метод выделяет предложение в параграфе. Предложение
     * ограничено с одной стороны строкой "firstLek", а с другой -
     * "lastLek".</p>
     * @param allPar Весь параграф
     * @param firstLek строка огранечитель с начала выходной строки
     * @param lastLek строка огранечитель с конца выходной строки
     * @return искомая строка
     */
    private String getSuggestionStrFromParagraph(String allPar, String firstLek,
            String lastLek) throws ArrayIndexOutOfBoundsException{
        //System.out.println("  >all>"+ allPar);
        String s [] = allPar.split(firstLek);
        String s1 = firstLek + s[1];
        if (s.length > 1 && s1.equals(s1.split(lastLek)[0])) {
            for (int i = 1; i < s.length; i++) {
                if(! s[i].equals(s[i].split(lastLek)[0])){
                    s1 = firstLek + s[i];
                    break;
                }
            }
        }
        //System.out.println("  >allPar.split("+firstLek+")[1]>"+ s1);
        if (s1.equals(firstLek + allPar)){
            //System.err.println("s1.equals(firstLek + allPar)");
            throw new ArrayIndexOutOfBoundsException();
        }
        if(s1.equals(s1.split(lastLek)[0])) {
            //System.err.println("s1.equals(s1.split(lastLek)[0])");
            //System.err.println("startsWith:" + allPar.startsWith(firstLek) + ":" + firstLek);
            //System.err.println("endsWith:" + allPar.endsWith(lastLek) + ":" + lastLek);
            //System.err.println("allPar:" + allPar);
            throw new ArrayIndexOutOfBoundsException();
        }
        String s2 = s1.split(lastLek)[0] + lastLek;
        //System.out.println("  >s1.split("+lastLek+")[0] + lastLek>"+ s2);
        String retStr = s2;
        return retStr;
    }

    /**
     * <p>Метод находит строку в заданной строке. Определяемая строка
     * с каждого края ограниченна двумя строками, находящихся в
     * заданой строке</p>
     * @param allS <p>заданная строка</p>
     * @param s1 <p>строковой огранечитель с левого края</p>
     * @param s2 <p>строковой огранечитель с правого края</p>
     * @return <p>подстрока в заданной строке </p>
     */
    private String getStrBetweenTwoSubStr(String allS, String s1, String s2){
        String retStr = "";
        String str1 = allS.split(s2)[0];
        //System.out.println("all=" + allS + ", s1=" + s1 + ", s2=" + s2);
        //System.out.println(">str1=allS.split(s2)[0]:"+str1);
        String str2 = str1.split(s1)[0] + s1;
        //System.out.println(">str2=str1.split(s1)[0]+s1:"+str2);
        retStr = str1.split(str2)[1];
        //System.out.println(">str1.split(str2)[1]:"+retStr);

        return retStr;
    }

    /**
     * <p>Метод добавляет к шапке обрабатываеемой таблици
     * дополнитель колонки из заголовка верхнего уравня</p>
     * @param docT заданная таблица
     * @param str массив добавляемых ячеек
     */
    @Override
    public void addHeadCellFromDocHead(DocTable docT, String [][] str){
        for (int i = 0; i < str[0].length; i++) {
            String s = "" + str[0][i];
            boolean tr = s.equals("null");
            if (!tr) {
                try {
                    docT.addHeadCell(str[0][i]);
                } catch (java.lang.ArrayIndexOutOfBoundsException e) {
                    System.err.println("  >can add head cell");
                    if (Keey.debug) {
                        e.printStackTrace();

                    }
                }
            }
        }
    }

    public static void toZeroTabCounter(){
        tabNum = -1;
    }

    public static int tabNum(){
        return tabNum;
    }

    /**
     * Опредедляет вернёт ли метод <b>getInfoInSuggestion</b> не пустуя
     * информацию
     * @param sb задаваемоя строка, в которой мы
     * ищем информацию
     * @param arr масив связок слов, которые разбивают
     * заданую строку
     * @param tr выводить ли номер обрабатываемой таблици и
     * увеличивать ли его на 1
     * @return масив указанный в описанеи
     */
    public boolean isInfoInSuggestion(StringBuffer sb, String [] arr, boolean tr){
        String [][] s = this.getInfoInSuggestion(sb, arr, tr);
        if(s == null)
            return false;
        for (int i = 0; i < s[0].length; i++) {
            if(s[0][i] != null && s[1][i] != null
                    && s[0][i] != "null" && s[1][i] != "null"
            //        && !s[0][i].equals("null") && !s[1][i].equals("null")
            ){
                return true;
            }
        }
        return false;
    }

}
